#include "threadPool.h"

int mysqlconnect(MYSQL **mysql)
{
    char *host = "localhost";
    char *user = "root";
    char *passwd = "123";
    char *database = "net_disk";

    *mysql = mysql_init(NULL);
    if (mysql_real_connect(*mysql, host, user, passwd, database, 0, NULL, 0) == NULL)
    {
        printf("Erorr : %s\n", mysql_error(*mysql));
        return -1;
    }
    return 0;
}

int do_query(char *query, MYSQL **mysql)
{
    int ret = mysql_query(*mysql, query);
    if (ret != 0)
    {
        printf("error query: %s\n", mysql_error(*mysql));
        return -1;
    }
    return 0;
}

// 初始化本地文件表
int init_local_file()
{
    // 连接数据库
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }

    char query[1024] = {0};

    // 读取目录流，获取本地存储目录中的每个文件
    DIR *dirp = opendir("Netdisk");
    ERROR_CHECK(dirp, NULL, "opendir");
    struct dirent *pdirent;
    char md5_str[MD5_STR_LEN + 1] = {0}; // 这里长度需要加1，存结束符

    while ((pdirent = readdir(dirp)) != NULL)
    {
        // 跳过隐藏文件
        if (*(pdirent->d_name) == '.')
        {
            continue;
        }
        char real_name[100] = {0};
        strcpy(real_name, pdirent->d_name);
        sprintf(query, "select * from local_files where real_file_name like '%s'", real_name);
        ret = do_query(query, &db);
        if (ret != 0)
        {
            return -1;
        }
        MYSQL_RES *result = mysql_store_result(db);
        if (ret != 0)
        {
            printf("Error : %s\n", mysql_error(db));
            return -1;
        }
        int rows = mysql_num_rows(result);
        if (rows != 0) // 文件名存在就继续读
        {
            mysql_free_result(result);
            continue;
        }
        mysql_free_result(result); // 文件名不存在则计算md5值，插入本地

        char path[1024] = {0};
        sprintf(path, "%s%s%s", "Netdisk", "/", pdirent->d_name);
        bzero(md5_str, sizeof(md5_str));
        Compute_file_md5(path, md5_str);
        bzero(query, sizeof(query));
        sprintf(query, "insert into local_files(md5, link_num, real_file_name) values('%s', 0, '%s')", md5_str, pdirent->d_name);
        ret = do_query(query, &db);
        if (ret != 0)
        {
            return -1;
        }
    }
    mysql_close(db);
    return 0;
}

// 服务端关闭时，将local_files表中链接数为0的文件真正删除，并将其从表中移除
int remove_local_file(){
    MYSQL *db;
    char path[1024] = {0};
    int ret = mysqlconnect(&db);
    if(ret != 0){
        return -1;
    }
    char query[1024] = {0};
    strcpy(query,"select real_file_name, md5 from local_files where link_num = '0'");
    ret = do_query(query,&db);
    if(ret != 0){
        return -1;
    }
    MYSQL_RES *result = mysql_store_result(db);
    if(result == NULL){
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    MYSQL_ROW row;
    while((row = mysql_fetch_row(result)) != NULL){
        //删除真实本地文件
        bzero(path,sizeof(path));
        sprintf(path,"Netdisk/%s",row[0]);
        unlink(path);
        //删除link_num = 0的表项
        bzero(query,sizeof(query));
        sprintf(query,"delete from local_files where md5 like '%s'",row[1]);
        do_query(query,&db);
    }
    mysql_free_result(result);
    mysql_close(db);
    return 0;
}

// 根据id从user_info中读出用户的当前目录的文件夹编号
int get_user_code(int user_id, int *pcode)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    ret = do_query("select id, code from user_info", &db);
    if (ret != 0)
    {
        return -1;
    }
    MYSQL_RES *result = mysql_use_result(db);
    if (result == NULL)
    {
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(result)) != NULL)
    {
        if (user_id == atoi(row[0]))
        {
            *pcode = atoi(row[1]);
            mysql_free_result(result);
            mysql_close(db);
            return 0;
        }
    }
    mysql_free_result(result);
    mysql_close(db);
    return -1;
}

// 根据id从user_info中读出用户的当前路径
int get_user_pwd(int user_id, char *pwd)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    ret = do_query("select id, pwd from user_info", &db);
    if (ret != 0)
    {
        return -1;
    }
    MYSQL_RES *result = mysql_use_result(db);
    if (result == NULL)
    {
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(result)) != NULL)
    {
        if (user_id == atoi(row[0]))
        {
            strcpy(pwd, row[1]);
            mysql_free_result(result);
            mysql_close(db);
            return 0;
        }
    }
    mysql_free_result(result);
    mysql_close(db);
    return -1;
}

// 根据当前文件夹编号，获取父节点id（上一级目录文件夹编号）
int get_parent_id(int id, int *pparent_code)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1000] = {0};
    sprintf(query, "select parent_id from fsystem where id ='%d'", id);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    MYSQL_RES *result = mysql_store_result(db);
    if (result == NULL)
    {
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    int row_num = mysql_num_rows(result);
    if (row_num == 0)
    { // 没有结果返回1
        mysql_free_result(result);
        mysql_close(db);
        return -1;
    }
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(result)) != NULL)
    {
        *pparent_code = atoi(row[0]);
        mysql_free_result(result);
        mysql_close(db);
        return 0;
    }
    mysql_free_result(result);
    mysql_close(db);
    return -1;
}

// 更新user_info中的pwd和code
int update_user_path(int user_id, char *pwd, int code)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1000] = {0};
    sprintf(query, "update user_info set code = '%d' where id = '%d'", code, user_id);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    bzero(query, sizeof(query));
    sprintf(query, "update user_info set pwd = '%s' where id = '%d'", pwd, user_id);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    mysql_close(db);
    return 0;
}

// 根据文件名和用户id获取文件在虚拟文件系统中的id, 类型
int get_file_code(int user_id, char *filename, int *pcode, int parent_id, char *type)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    sprintf(query, "select id, type from fsystem where filename like '%s' and owner_id = '%d' and parent_id = '%d'", filename, user_id, parent_id);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    MYSQL_RES *result = mysql_use_result(db);
    if (result == NULL)
    {
        printf("Erorr : %s\n", mysql_error(db));
        return -1;
    }
    MYSQL_ROW row;
    if ((row = mysql_fetch_row(result)) == NULL) // 不存在直接返回
    {
        return -1;
    }
    *pcode = atoi(row[0]);
    strcpy(type, row[1]);
    mysql_free_result(result);
    mysql_close(db);
    return 0;
}

// 获取文件md5值，也可以检查文件是否存在，存在返回0，不存在返回1
int get_fsystem_md5(char *file, int user_id, int parent_id, char *md5_str)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    sprintf(query, "select md5 from fsystem where owner_id = '%d' and parent_id = '%d' and filename like '%s'", user_id, parent_id, file);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    MYSQL_RES *result = mysql_use_result(db);
    if (result == NULL)
    {
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    MYSQL_ROW row;
    if ((row = mysql_fetch_row(result)) == NULL) // 不存在则直接返回
    {
        return -1;
    }
    strcpy(md5_str, row[0]);
    mysql_free_result(result);
    mysql_close(db);
    return 0;
}

// 增加虚拟文件
int add_fsystem_file(int parent_id, char *filename, int owner_id, char *md5_str, off_t filesize)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    sprintf(query, "insert into fsystem (parent_id, filename, owner_id, md5, filesize, type) values(%d, '%s', %d, '%s', %ld, 'f')", parent_id, filename, owner_id, md5_str, filesize);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    mysql_close(db);
    return 0;
}

// 删除虚拟文件
int del_fsystem_file(int code, int user_id)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    sprintf(query, "delete from fsystem where id = %d", code);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    bzero(query, sizeof(query));
    sprintf(query, "delete from fsystem where parent_id = %d and owner_id = %d", code, user_id);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }

    mysql_close(db);
    return 0;
}

// 增加虚拟文件夹
int add_fsystem_dir(int parent_id, char *dirname, int owner_id)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    sprintf(query, "insert into fsystem (parent_id, filename, owner_id, md5, filesize, type) values(%d, '%s', %d, '0', 0, 'd')", parent_id, dirname, owner_id);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    mysql_close(db);
    return 0;
}

// 查看本地文件表是否已经有该文件存在
int if_local_exist(char *md5_str)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    sprintf(query, "select * from local_files where md5 like '%s'", md5_str);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    MYSQL_RES *result = mysql_store_result(db);
    if (result == NULL)
    {
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    int row = mysql_num_rows(result);
    if (row == 0)
    {
        mysql_free_result(result);
        return -1;
    }
    mysql_free_result(result);
    mysql_close(db);
    return 0;
}

// 获取文件本地真实名称
int get_real_file_name(char *md5_str, char *real_file_name)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    // 按照md5值在表中查找本地文件名
    sprintf(query, "select real_file_name from local_files where md5 like '%s'", md5_str);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    MYSQL_RES *result = mysql_store_result(db);
    if (result == NULL)
    {
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    int rows = mysql_num_rows(result);
    if (rows == 0) // 文件不存在返回1
    {
        mysql_free_result(result);
        mysql_close(db);
        return 1;
    }
    MYSQL_ROW row;
    if ((row = mysql_fetch_row(result)) == NULL)
    {
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    strcpy(real_file_name, row[0]);
    mysql_free_result(result);
    mysql_close(db);
    return 0;
}

// 增加本地文件的链接数
int add_link(char *md5_str)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    sprintf(query, "update local_files set link_num = link_num + 1 where md5 like '%s'", md5_str);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    mysql_close(db);
    return 0;
}

// 减少本地文件的链接数
int minus_file_link(char *md5_str)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    sprintf(query, "select link_num from local_files where md5 like '%s'", md5_str);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    MYSQL_RES *result = mysql_store_result(db);
    if (result == NULL)
    {
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    MYSQL_ROW row;
    int link_num; // 获取当前链接数
    if ((row = mysql_fetch_row(result)) == NULL)
    {
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    link_num = atoi(row[0]);
    if (link_num == 0)
    {
        printf("error minus link_num!\n");
        return -1;
    }
    bzero(query, sizeof(query));
    sprintf(query, "update local_files set link_num = link_num - 1 where md5 like '%s'", md5_str);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    mysql_close(db);
    return 0;
}

// 减少目标目录下所有文件的链接数
int minus_dir_link(MYSQL **mysql, int user_id, int dir_id)
{
    int code;
    char query[1024] = {0};
    sprintf(query, "select id, filename, type from fsystem where owner_id = '%d' and parent_id = '%d'", user_id, dir_id);
    int ret = do_query(query, mysql);
    if (ret != 0)
    {
        return -1;
    }
    MYSQL_RES *result = mysql_store_result(*mysql);
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(result)) != NULL)
    {
        code = atoi(row[0]);
        if (strcmp(row[2], "d") == 0)
        {
            minus_dir_link(mysql, user_id, code);
        }
        else
        {
            char md5_str[MD5_STR_LEN + 1] = {0};
            get_fsystem_md5(row[1], user_id, dir_id, md5_str); // 要先查询再删除
            ret = minus_file_link(md5_str);                    // 本地链接数减一
        }
    }
    mysql_free_result(result);
    return 0;
}

// 在本地文件表中新增内容
int add_local_file(char *md5_str, char *real_name)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    int link_num;
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    sprintf(query, "insert into local_files(md5, link_num, real_file_name) values('%s', 1, '%s')", md5_str, real_name);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    mysql_close(db);
    return 0;
}

// ls功能的实现，把文件id为code的文件夹下的文件全部发给客户端
int find_code_files(int netFd, int code, int user_id)
{
    MYSQL *db;
    int ret = mysqlconnect(&db);
    if (ret != 0)
    {
        return -1;
    }
    char query[1024] = {0};
    sprintf(query, "select filename from fsystem where parent_id = %d and owner_id = %d", code, user_id);
    ret = do_query(query, &db);
    if (ret != 0)
    {
        return -1;
    }
    MYSQL_RES *result = mysql_use_result(db);
    if (result == NULL)
    {
        printf("Error : %s\n", mysql_error(db));
        return -1;
    }
    MYSQL_ROW row;
    train_t train;
    while ((row = mysql_fetch_row(result)) != NULL)
    {
        train.length = strlen(row[0]);
        bzero(train.data, sizeof(train.data));
        strcpy(train.data, row[0]);
        send(netFd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    }
    // 发送长度0表示结束
    train.length = 0;
    send(netFd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    mysql_free_result(result);
    mysql_close(db);
    return -1;
}
